home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Utilities / Other / mCD / Source / scsi_cd.subproj / scsi_commands.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-19  |  9.7 KB  |  387 lines

  1. /*
  2.  * scsi_commands.c: scsi command functions
  3.  *
  4.  * This is based on the file that NeXT included in
  5.  *      /NextDeveloper/Examples/UNIX/SCSI_CD,
  6.  *      done by James C. Lee at NeXT, Sep 1991, and updated by him
  7.  *    in Feb 1993.  He, in turn, got a lot of data structures &
  8.  *    function calls from a perftest.c program done by Mike DeMoney.
  9.  * It has been changed "just a bit" by Garance Alistair Drosehn/March 1994,
  10.  *      to add a few routines and make a few minor changes to some others.
  11.  *
  12.  */
  13.  
  14. #import <sys/time.h>
  15. #import <bsd/dev/disk.h>
  16. #import <stdio.h>
  17. #import <libc.h>
  18. #import <stdlib.h>
  19. #import "scsi_commands.h"
  20.  
  21. /* I use a copy of the NS-3.1 version of bsd/dev/scsireg.h, because
  22.  * at some point I think I want to split it apart into "field values"
  23.  * (such as #define DEVTYPE_DISK), and actual structure definitions.
  24.  *                  Garance Drosehn/Mar 94
  25.  */
  26. /* #import <bsd/dev/scsireg.h> */
  27. #import "scsireg_31.h"        /* garance... */
  28.  
  29.  
  30. void fatal(const char *msg, ...)
  31. {
  32.     va_list ap;
  33.  
  34.     va_start(ap, msg);
  35. /*    fprintf(stderr, "%s: ", progname);*/
  36.     vfprintf(stderr, msg, ap);
  37.     fprintf(stderr, "\n");
  38.     va_end(ap);
  39.  
  40.     exit(1);
  41. }
  42.  
  43. inline int is_pow2(int i)
  44. {
  45.     return (i & (i - 1)) == 0;
  46. }
  47.  
  48. int do_inquiry(int fd, struct inquiry_reply *irp, struct esense_reply *erp)
  49. {
  50.     struct scsi_req sr;
  51.     struct cdb_6 *c6p;
  52.     int err;
  53.  
  54.     bzero((char *)&sr, sizeof(sr));
  55.  
  56.     c6p = (struct cdb_6 *)&sr.sr_cdb;
  57.     c6p->c6_opcode = C6OP_INQUIRY;
  58.     c6p->c6_len = sizeof(*irp);
  59.  
  60.     sr.sr_addr = (char *)irp;
  61.     sr.sr_dma_max = sizeof(*irp);
  62.     sr.sr_ioto = 5;
  63.     sr.sr_dma_dir = SR_DMA_RD;
  64.  
  65.     err = ioctl(fd, SDIOCSRQ, &sr);
  66.     *erp = sr.sr_esense;
  67.     return err | sr.sr_io_status;
  68. }
  69.  
  70.  
  71. /**************************************************************************
  72.  * NOTE: It turns out that the following routine might not be all that
  73.  *     safe to call.  The man page for sg (the generic scsi driver)
  74.  *     mentions that it's "extremely hazardous" to bind the generic
  75.  *     scsi device (using SGIOCSTL) to a device that some other
  76.  *     SCSI driver is already using.  I don't know if doing just a
  77.  *     inquiry command is hazardous, but this does sometimes cause
  78.  *     the machine to freeze up for short period of time when it's
  79.  *     doing the inquiry command on the bootup disk.
  80.  *     
  81.  *     Someone who knows more about SCSI programming than I do will
  82.  *     need to look this over, I guess.   Garance Drosehn/Mar 19/94
  83.  */
  84. int do_inquiryall(int replyCount, struct inquiry_all_reply *all,
  85.     struct esense_reply *erp)
  86. {
  87.     struct scsi_adr    scsiAddress;
  88.     struct inquiry_reply *thisIrp;
  89.     struct scsi_req sr;
  90.     struct cdb_6 *c6p;
  91.     int err, index, maxIndex, diskIndex, tryCount;
  92.     int tempFd = 0;
  93.  
  94.     /* Open up one of the generic SCSI device drivers */
  95.     tempFd = open("/dev/sg0", O_RDONLY );
  96.     if (tempFd == -1) tempFd = open("/dev/sg1", O_RDONLY );
  97.     if (tempFd == -1)
  98.         return 0;  /* failed */
  99.     
  100.     /* for now, assume there's only one SCSI controller with
  101.      * 8 devices (id's 0 thru 7, where 7 is the computer).
  102.      * I make this assumption because I have no idea what
  103.      * to do if there are multiple SCSI controllers...
  104.      */
  105.     maxIndex = replyCount;
  106.     if ( replyCount > INQ_ALL_MAX_SCSI_CNT )
  107.         maxIndex = INQ_ALL_MAX_SCSI_CNT;
  108.     all->maxScsiCount = maxIndex;
  109.     
  110.     /* Go through all the devices in the /dev directory */
  111.     diskIndex = 0;
  112.     for(index = 0; index < maxIndex; index++) {
  113.         bzero((char *)&scsiAddress, sizeof(scsiAddress));
  114.         
  115.         /* Set the scsi address */
  116.         scsiAddress.sa_target = index;
  117.         scsiAddress.sa_lun = 0;
  118.         
  119.         /* Tell the driver what device we want to talk to */
  120.         err = ioctl(tempFd, SGIOCSTL, &scsiAddress);
  121.  
  122.         /* Check for an error */
  123.         if (err == -1) {    
  124.         close(tempFd);
  125.         fatal("do_inquiryall: unable to set SCSI address");
  126.         }
  127.  
  128.         thisIrp = &(all->scsiArray[index].inqResult);
  129.         tryCount = 0;
  130.         try_again:
  131.         tryCount++;
  132.         
  133.         bzero((char *)&sr, sizeof(sr));
  134.     
  135.         c6p = (struct cdb_6 *)&sr.sr_cdb;
  136.         c6p->c6_opcode = C6OP_INQUIRY;
  137.         c6p->c6_len = sizeof(*thisIrp);
  138.     
  139.         sr.sr_addr = (char *)thisIrp;
  140.         sr.sr_dma_max = sizeof(*thisIrp);
  141.         sr.sr_ioto = 90;  /* timeout */
  142.         sr.sr_dma_dir = SR_DMA_RD;
  143.     
  144.         /* this routine can't call do_inquiry here because it
  145.            needs to do an SGIOCREQ instead of SDIOCREQ */
  146.         err = ioctl(tempFd, SGIOCREQ, &sr);
  147.         *erp = sr.sr_esense;
  148.         all->scsiArray[index].devIoStat = sr.sr_io_status;
  149.         all->scsiArray[index].deviceNumber = -1;
  150.         switch (sr.sr_io_status) {
  151.            case SR_IOST_GOOD:
  152.             if(tryCount > 1) {
  153.             printf("scsi-cmd debug: scsi_id= %d OK on try#=%d\n",
  154.                 index, tryCount);
  155.             }
  156.             all->scsiArray[index].deviceNumber = diskIndex++;
  157.             break;
  158.            case SR_IOST_SELTO:
  159.                    /* it seems we get a "selection timeout" if there is
  160.              * no device with this scsi ID.  Do Nothing */
  161.              break;
  162.            case SR_IOST_CHKSV:
  163.            case SR_IOST_CHKSNV:
  164.             /* if these come up, then there is a device here.
  165.              * Retrying it often seems to be the cure, though
  166.              * one should *-> NOTE <-* that I have no idea if
  167.              * that is the right thing to do at this point...
  168.              * Also NOTE that when this happens, the machine
  169.              * tends to freeze up for about 10-20 seconds.
  170.              */
  171.             if (tryCount < 2) goto try_again;
  172.             all->scsiArray[index].deviceNumber = diskIndex++;
  173.            default:
  174.             /* probably need to do something with any other
  175.              * io_status values, but what?  In some cases a
  176.              * retry might make sense, or maybe incrementing
  177.              * the disk index to at least skip over the device.
  178.              * Perhaps a SGIOCRST to reset the scsi bus?
  179.              */
  180.             printf("scsi-cmd debug: scsi_id= %d, io_stat= %d try#=%d\n",
  181.                     index, sr.sr_io_status, tryCount);
  182.             break;
  183.         }
  184.         }
  185.  
  186.     if (tempFd > -1) close(tempFd);
  187.     return 1;    /* seems to have succeeded */
  188. }
  189.  
  190. int do_testunitready(int fd, struct timeval *tvp, struct esense_reply *erp)
  191. {
  192.     struct scsi_req sr;
  193.     struct cdb_6 *c6p;
  194.     int err;
  195.  
  196.     bzero((char *)&sr, sizeof(sr));
  197.  
  198.     c6p = (struct cdb_6 *)&sr.sr_cdb;
  199.     c6p->c6_opcode = C6OP_TESTRDY;
  200.  
  201.     sr.sr_addr = NULL;
  202.     sr.sr_dma_max = 0;
  203.     sr.sr_ioto = 5;
  204.     sr.sr_dma_dir = SR_DMA_RD;
  205.  
  206.     err = ioctl(fd, SDIOCSRQ, &sr);
  207.  
  208.     *tvp = sr.sr_exec_time;
  209.  
  210.     *erp = sr.sr_esense;
  211.     return err | sr.sr_io_status;
  212. }
  213.  
  214. int do_modesense(int fd, struct mode_sense_reply *msrp, int page,
  215.     struct esense_reply *erp)
  216. {
  217.     struct scsi_req sr;
  218.     struct mode_sense_cmd *mscp;
  219.     int err;
  220.  
  221.     bzero((char *)&sr, sizeof(sr));
  222.  
  223.     mscp = (struct mode_sense_cmd *)&sr.sr_cdb;
  224.     mscp->msc_opcode = C6OP_MODESENSE;
  225.     mscp->msc_pcf = 0;    /* report current values */
  226.     mscp->msc_page = page;
  227.     mscp->msc_len = sizeof(*msrp);
  228.  
  229.     sr.sr_addr = (char *)msrp;
  230.     sr.sr_dma_max = sizeof(*msrp);
  231.     /*
  232.      * Extend timeout so Quantum drive works with test.
  233.      */
  234.     sr.sr_ioto = 50;
  235.     sr.sr_dma_dir = SR_DMA_RD;
  236.  
  237.     err = ioctl(fd, SDIOCSRQ, &sr);
  238.  
  239.     printf("sr.sr_io_status: %d\n", sr.sr_io_status);
  240.     *erp = sr.sr_esense;
  241.     return err | sr.sr_io_status;
  242. }
  243.  
  244. int do_readcapacity(int fd, struct capacity_reply *crp,
  245.     struct esense_reply *erp)
  246. {
  247.     struct scsi_req sr;
  248.     struct cdb_10 *c10p;
  249.     int err;
  250.  
  251.     bzero((char *)&sr, sizeof(sr.sr_cdb));
  252.  
  253.     c10p = (struct cdb_10 *)&sr.sr_cdb;
  254.     c10p->c10_opcode = C10OP_READCAPACITY;
  255.  
  256.     sr.sr_addr = (char *)crp;
  257.     sr.sr_dma_max = sizeof(*crp);
  258.     sr.sr_ioto = 5;
  259.     sr.sr_dma_dir = SR_DMA_RD;
  260.  
  261.     err = ioctl(fd, SDIOCSRQ, &sr);
  262.     *erp = sr.sr_esense;
  263.     return err | sr.sr_io_status;
  264. }
  265.  
  266. int do_seek(int fd, int lba, struct timeval *tvp, struct esense_reply *erp)
  267. {
  268.     struct scsi_req sr;
  269.     struct cdb_6 *c6p;
  270.     int err;
  271.  
  272.     bzero((char *)&sr, sizeof(sr));
  273.  
  274.     c6p = (struct cdb_6 *)&sr.sr_cdb;
  275.     c6p->c6_opcode = C6OP_SEEK;
  276. #ifdef i386
  277.     if (lba > 0) {
  278.         c6p->c6_lba0 = lba & 0xFF;
  279.         c6p->c6_lba1 = (lba >> 8) & 0xFF;
  280.         c6p->c6_lba2 = (lba >> 16) & 0xFF;
  281.     } else
  282.         c6p->c6_lba0 = c6p->c6_lba1 = c6p->c6_lba2 = 0;
  283. #else
  284.     c6p->c6_lba = lba;
  285. #endif
  286.  
  287.     sr.sr_addr = 0;
  288.     sr.sr_dma_max = 0;    /* don't really do I/O to memory */
  289.     sr.sr_ioto = 5;
  290.     sr.sr_dma_dir = SR_DMA_RD;
  291.  
  292.     err = ioctl(fd, SDIOCSRQ, &sr);
  293.  
  294.     *tvp = sr.sr_exec_time;
  295.  
  296.     *erp = sr.sr_esense;
  297.     return err | sr.sr_io_status;
  298. }
  299.  
  300. int do_read(int fd, int lba, int nblks, struct timeval *tvp,
  301.     struct esense_reply *erp)
  302. {
  303.     struct scsi_req sr;
  304.     struct cdb_6 *c6p;
  305.     int err;
  306.  
  307.     if (nblks > 256)
  308.         fatal("Too many blocks for read: %d", nblks);
  309.     if (nblks == 256)
  310.         nblks = 0;
  311.  
  312.     bzero((char *)&sr, sizeof(sr));
  313.  
  314.     c6p = (struct cdb_6 *)&sr.sr_cdb;
  315.     c6p->c6_opcode = C6OP_READ;
  316. #ifdef i386
  317.     if (lba > 0) {
  318.         c6p->c6_lba0 = lba & 0xFF;
  319.         c6p->c6_lba1 = (lba >> 8) & 0xFF;
  320.         c6p->c6_lba2 = (lba >> 16) & 0xFF;
  321.     } else
  322.         c6p->c6_lba0 = c6p->c6_lba1 = c6p->c6_lba2 = 0;
  323. #else
  324.     c6p->c6_lba = lba;
  325. #endif
  326.     c6p->c6_len = nblks;
  327.  
  328.     sr.sr_addr = NULL;
  329.     sr.sr_dma_max = 0;    /* don't really do I/O to memory */
  330.     sr.sr_ioto = 5;
  331.     sr.sr_dma_dir = SR_DMA_RD;
  332.  
  333.     err = ioctl(fd, SDIOCSRQ, &sr);
  334.  
  335.     *tvp = sr.sr_exec_time;
  336.  
  337.     if (sr.sr_dma_xfr != 0)
  338.         fatal("scsi driver did transfer: %d", sr.sr_dma_xfr);
  339.  
  340.     *erp = sr.sr_esense;
  341.     return err | sr.sr_io_status;
  342. }
  343.  
  344. int do_write(int fd, int lba, int nblks, struct timeval *tvp,
  345.     struct esense_reply *erp)
  346. {
  347.     struct scsi_req sr;
  348.     struct cdb_6 *c6p;
  349.     int err;
  350.  
  351.     if (nblks > 256)
  352.         fatal("Too many blocks for read: %d", nblks);
  353.     if (nblks == 256)
  354.         nblks = 0;
  355.  
  356.     bzero((char *)&sr, sizeof(sr));
  357.  
  358.     c6p = (struct cdb_6 *)&sr.sr_cdb;
  359.     c6p->c6_opcode = C6OP_WRITE;
  360. #ifdef i386
  361.     if (lba > 0) {
  362.         c6p->c6_lba0 = lba & 0xFF;
  363.         c6p->c6_lba1 = (lba >> 8) & 0xFF;
  364.         c6p->c6_lba2 = (lba >> 16) & 0xFF;
  365.     } else
  366.         c6p->c6_lba0 = c6p->c6_lba1 = c6p->c6_lba2 = 0;
  367. #else
  368.     c6p->c6_lba = lba;
  369. #endif
  370.     c6p->c6_len = nblks;
  371.  
  372.     sr.sr_addr = NULL;
  373.     sr.sr_dma_max = 0;    /* don't really do I/O to memory */
  374.     sr.sr_ioto = 5;
  375.     sr.sr_dma_dir = SR_DMA_WR;
  376.  
  377.     err = ioctl(fd, SDIOCSRQ, &sr);
  378.  
  379.     *tvp = sr.sr_exec_time;
  380.  
  381.     if (sr.sr_dma_xfr != 0)
  382.         fatal("scsi driver did transfer: %d", sr.sr_dma_xfr);
  383.  
  384.     *erp = sr.sr_esense;
  385.     return err | sr.sr_io_status;
  386. }
  387.